/**
 * 
 */
package stc.skymobi.bean.tlv.encode.encoders;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import stc.skymobi.bean.tlv.annotation.TLVAttribute;
import stc.skymobi.bean.tlv.encode.TLVEncodeContext;
import stc.skymobi.bean.tlv.encode.TLVEncodeContextFactory;
import stc.skymobi.bean.tlv.encode.TLVEncoder;
import stc.skymobi.util.ByteUtils;


/**
 * @author marvin.ma
 *
 */
public class ObjectArrayTLVEncoder implements TLVEncoder {

    private static final Logger LOG = 
        	LoggerFactory.getLogger(ObjectArrayTLVEncoder.class);
    
    private	TLVEncodeContextFactory	encodeContextFactory;
    
	public TLVEncodeContextFactory getEncodeContextFactory() {
		return encodeContextFactory;
	}

	public void setEncodeContextFactory(TLVEncodeContextFactory encodeContextFactory) {
		this.encodeContextFactory = encodeContextFactory;
	}
	
    /* (non-Javadoc)
     * @see com.skymobi.util.Transformer#transform(java.lang.Object)
     */
	public List<byte[]> encode(final Object src, final TLVEncodeContext ctx) {
		
		if ( !ctx.getValueType().isArray() ) {
			LOG.error("encode object's type {} is not array type", ctx.getValueType());
			return	null;
		}
		
		final Field field = ctx.getValueField();
        final TLVAttribute param  = field.getAnnotation(TLVAttribute.class);
        if ( -1 == param.elementTag() ) {
        	LOG.error("Array field[{}]'s elementTag not define, ignore", field);
        	return	null;
        }
		
		final Class<?> elementType = ctx.getValueType().getComponentType();
        final TLVEncoder encoder = ctx.getEncoderRepository().getEncoderOf(elementType);
        if ( null == encoder ) {
        	LOG.error("Array field[{}]/{} can not found encoder, ignore", 
        			field, elementType.getSimpleName());
        	return	null;
        }

        final List<byte[]> ret = new ArrayList<byte[]>();
        
        for ( Object element : (Object[])src ) {
            final List<byte[]> dest = encoder.encode(element, 
            		encodeContextFactory.createEncodeContext(elementType, field) );
            //	tag
            ret.add( ctx.getNumberCodec().int2Bytes(param.elementTag(), 4) );
            
            //	len
            ret.add( ctx.getNumberCodec().int2Bytes(ByteUtils.totalByteSizeOf(dest), 4) );
            
            ret.addAll(dest);
        }
        return ret;
	}

}
